/** 
 * This file is a part of qloudgen-sec. 
 * You can redistribute qloudgen-sec and/or modify it under the terms of the Lesser GNU General Public License version 3. 
 * qloudgen-sec is distributed WITHOUT ANY WARRANTY. 
 *
 * See the Lesser GNU General Public License for more details at http://www.gnu.org/licenses/. 
 **/
package org.qloudgen.sec.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>Title: Thread tools.</p>
 * <p>Description: Implementation single thread from block to end.</p>
 * <p>Copyright: qloudgen/sec 2011</p>
 * @author <a href="mailto:hyq.dd.sun@gmail.com">glue.3M</a>
 */
public final class ThreadBlockUtil {
	
	/**
	 * Thread block exception.
	 */
	public class ThreadBlockException extends Exception {
		/**
		 * Custom constructor.
		 *
		 * @param message
		 * @param cause
		 */
		public ThreadBlockException(String message , Throwable cause) {
			super( message , cause );
		}
	}
	
	/**
	 * Log output.
	 */
	private final static Logger logger = LoggerFactory.getLogger( ThreadBlockUtil.class );
	/**
	 * Thread end flag.
	 */
	private boolean isDone = false;
	
	/**
	 * Default constructor.
	 */
	public ThreadBlockUtil() {
	}

	/**
	 * Waiting notify
	 *
	 * @param timeout
	 * @throws ThreadBlockException
	 */
	public void waitTillDone(long timeout) throws ThreadBlockException {
		//
		synchronized( this ) {
			//
			while ( ! isDone ) {
				//
				logger.info( "Current thread waiting till done..." + Thread.currentThread().toString() );
				// Waiting notify from monitor thread.
				try {
					if ( timeout < 0 ) {
						// Wait forever.
						wait();
					}
					else {
						// Wait
						wait( timeout );
						// Not receive notify, Just exit.
						isDone = true;
					}
				}
				catch(InterruptedException ie) {
					throw new ThreadBlockException( "InterruptedException:waitTillDone()" , ie );
				}
				catch(IllegalMonitorStateException imse) {
					throw new ThreadBlockException( "IllegalMonitorStateException:waitTillDone()" , imse );
				}
			}
			//
			logger.info( "Current thread is done..." + Thread.currentThread().toString() );
		}
	}
	
	/**
	 * End notify
	 *
	 * @throws ThreadBlockException
	 */
	public void allDone() throws ThreadBlockException {
		//
		synchronized( this ) {
			//
			logger.info( "Current thread will be done..." + Thread.currentThread().toString() );
			//
			isDone = true;
			// Send notify to monitor thread.
			try {
				notify();
			}
			catch(IllegalMonitorStateException imse) {
				throw new ThreadBlockException( "IllegalMonitorStateException:allDone()" , imse );
			}
		}
	}
	
	/**
	 * Reset
	 */
	public void reset() {
		//
		synchronized( this ) {
			isDone = false;
		}
	}
}